/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H
#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H

#include <list>
#include "imageknife.h"
#include "imageknife_node_internal.h"
#include "dns/dns_option_internal.h"

namespace ImageKnifePro {

class ImageKnifeInternal : public ImageKnife {
public:
    static ImageKnifeInternal& GetInstance();

    void Init() override;
    void InitImageKnifeArkTs(napi_env env, napi_value &exports) override;
    void SetRootNode(std::string id, ArkUI_NodeContentHandle handle, std::shared_ptr<ImageKnifeNodeInternal> node);
    void SetImageNode(std::shared_ptr<ImageKnifeNodeInternal> node);

    void Execute(std::shared_ptr<ImageKnifeRequest> request);

    void CancelRequest(std::shared_ptr<ImageKnifeRequest> request) override;

    std::shared_ptr<ImageKnifeLoader> GetDefaultImageKnifeLoader() const;

    void SetDefaultImageKnifeLoader(std::shared_ptr<ImageKnifeLoader> imageLoader) override;

    std::shared_future<void> InitFileCacheAsync(std::string sandbox = "", size_t size = 256,
                                                size_t maxDiskUsage = 256 * 1024 * 1024,
                                                std::string path = "ImageKnife") override ;

    void InitFileCache(std::string sandbox = "", size_t size = 256,
                       size_t maxDiskUsage = 256 * 1024 * 1024, std::string path = "ImageKnife");

    CacheErrorCode AddSmallEndFileCache(std::string cacheName, std::string sandbox, std::string path) override;

    std::shared_future<void> InitSmallEndFileCache(std::string cacheName, size_t size = 128,
                                                   size_t maxDiskUsage = 128 * 1024 * 1024) override;

    void InitSmallEndFileCacheSync(std::string cacheName, size_t size = 128, size_t maxDiskUsage = 128 * 1024 * 1024);

    void FileCacheEnableExtension(std::string cacheName = "") override;
    bool IsFileCacheInit(std::string cacheName = "") override;

    void SetCacheKeyGenerator(CacheKeyGenerator *keyPtr) override;

    CacheKeyGenerator *GetCacheKeyGenerator() const;

    std::shared_ptr<ImageKnifeRequest> Preload(std::shared_ptr<ImageKnifeOption> imageKnifeOption) override;

    void SetMaxRequests(int concurrency) override;

    void SetCacheLimit(CacheStrategy cacheStrategy, size_t maxSize, size_t maxUsage,
                       std::string cacheName = "") override;

    int64_t GetCacheLimitNum(CacheStrategy cacheStrategy, std::string cacheName = "") override;
    int64_t GetCacheLimitSize(CacheStrategy cacheStrategy, std::string cacheName = "") override;

    int64_t GetCurrentCacheNum(CacheStrategy cacheStrategy, std::string cacheName = "") override;

    int64_t GetCurrentCacheSize(CacheStrategy cacheStrategy, std::string cacheName = "") override;
    void DisposeImageNode(std::string id);

    std::shared_ptr<ImageKnifeNodeInternal> GetImageNode(std::string id);
    std::shared_ptr<ImageKnifeNodeInternal> GetPreCreatedNode(std::string id, bool remove = false);
    void SetPreCreatedNode(std::string id, std::shared_ptr<ImageKnifeNodeInternal> node);
    void SetMaxPreCreateNodeCount(size_t maxCount);
    void ReleasePreCreatedNode();
    size_t GetPreCreatedNodeCout();

    void RemoveFileCache(std::string &url, std::string cacheName);
    void RemoveFileCache(std::shared_ptr<ImageKnifeOption> option);
    void RemoveAllFileCache(std::string cacheName = "");
    std::shared_future<void> RemoveFileAsync(std::string url, std::string cacheName = "") override;
    std::shared_future<void> RemoveFileAsync(std::shared_ptr<ImageKnifeOption> option) override;
    std::shared_future<void> RemoveAllFileAsync(std::string cacheName = "") override;
    void RemoveFileAsync(std::shared_ptr<ImageKnifeOption> option, std::function<void()> onComplete) override;
    void RemoveAllFileAsync(std::function<void()> onComplete, std::string cacheName = "") override;

    void RemoveAllMemoryCache() override;
    void RemoveMemoryCache(std::string url) override;
    void RemoveMemoryCache(std::shared_ptr<ImageKnifeOption> imageKnifeOption) override;

    void RegisterLoader(std::string name, std::shared_ptr<ImageKnifeLoader> loader) override;
    void RegisterTransformation(std::string name, std::shared_ptr<Transformation> transformation) override;
    void RegisterTransformationConstructor(std::string name,
                                           std::shared_ptr<TransformationConstructor> constructor) override;

    void Reload(std::string requestId) override;

    std::shared_ptr<ImageKnifeLoader> GetRegisterLoader(std::string name);
    void PutCacheImage(std::string url, std::shared_ptr<ImageData> imageData,
                       CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "",
                       std::string cacheName = "") override;
    std::shared_ptr<Transformation> GetRegisterTransformation(std::string name);
    std::shared_ptr<TransformationConstructor> GetRegisterTransformationConstructor(std::string name);

    void AddHeader(std::string key, std::string value) override;
    void DeleteHeader(std::string key) override;
    const std::multimap<std::string, std::string> &GetGlobalHttpHeaders();
    void SetGlobalDnsOption(std::shared_ptr<DnsOption> dnsOption) override;
    std::shared_ptr<DnsOptionInternal> GetGlobalDnsOption() const;

    std::shared_future<std::string> PreloadCache(std::shared_ptr<ImageKnifeOption> option) override;
    void PreloadCache(std::shared_ptr<ImageKnifeOption> option, std::function<void(std::string)> onComplete) override;

    void GetCacheImage(std::shared_ptr<Promise<std::shared_ptr<ImageData>>> promise,
        std::shared_ptr<ImageKnifeOption> option, CacheStrategy cacheType, std::string signature, bool animator);
    void GetCacheImage(std::shared_ptr<ImageKnifeOption> option,
        std::function<void(std::shared_ptr<ImageData>)> onComplete,
        CacheStrategy cacheType = CacheStrategy::DEFAULT) override;

    std::shared_future<std::shared_ptr<ImageData>> GetCacheImage(std::string loadSrc,
        CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "",  bool animator = false) override;

    std::shared_future<std::shared_ptr<ImageData>> GetCacheImage(std::shared_ptr<ImageKnifeOption> option,
        CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "", bool animator = false) override;

    void SetCustomLogPrinter(LogPrinter logPrinter) override;
    void SetFileTypeParser(std::shared_ptr<FileTypeParser> fileTypeParser) override;
    std::shared_ptr<FileTypeParser> GetFileTypeParser() const;

private:
    std::unordered_map<std::string, std::shared_ptr<ImageKnifeNodeInternal>> imageNodeMap_;
    std::unordered_map<std::string, std::shared_ptr<ImageKnifeNodeInternal>> preCreatedNodeMap_;
    std::list<std::string> preCreatedNodeIdList_;
    size_t maxPreCreateNodeCount_;

    std::unordered_map<std::string, std::shared_ptr<ImageKnifeLoader>> loaderMap_;

    std::unordered_map<std::string, std::shared_ptr<Transformation>> transformationMap_;
    std::unordered_map<std::string, std::shared_ptr<TransformationConstructor>> transformationConstructorMap_;

    std::shared_ptr<FileTypeParser> fileTypeParser_ = nullptr;
    std::shared_ptr<ImageKnifeLoader> imageLoader_ = nullptr;
    CacheKeyGenerator *keyPtr_ = nullptr;

    std::multimap<std::string, std::string> httpHeaders_;
    std::shared_ptr<DnsOptionInternal> dnsOption_ = nullptr;

    ImageKnifeInternal();
    ImageKnifeInternal(const ImageKnifeInternal&) = delete;
    ImageKnifeInternal &operator = (const ImageKnifeInternal&) = delete;
    friend ImageKnife &ImageKnife::GetInstance();

    ~ImageKnifeInternal() override
    {
        if (keyPtr_ != nullptr) {
            delete keyPtr_;
            keyPtr_ = nullptr;
        }
    }
};

} // end of namespace

#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H
